#include "base/channel.h"
#include "base/eventloop.h"
#include "base/eventloopthread.h"
#include "base/log.h"
#include "base/logthread.h"
#include "base/threadpool.h"
#include "net/connect.h"
#include "net/connectpool.h"
#include "net/socket.h"

#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>

#include "net/tcpclient.h"
namespace net_tools{

Tcpclient::Tcpclient()
  :socket_(new net::Socket()),
   before_loop_todo_([](Eventloop* eventloop){;}),
   connect_over_callback_([](net::Connect* connect){connect->Print_ip_port("connect");}),
   message_callback_(Default_message),
   close_callback_(Default_close)
{
  socket_->Set_noblocked(socket_->Get_socket());
  signal(SIGPIPE,SIG_IGN);
};
bool Tcpclient::Startclient(bool loop,std::string& ipaddr,int port,int work_thread_number,int mempool_block_number,int mempool_block_size){
  net::Connect::threadpool_ = new net_tools::base::Threadpool(work_thread_number);
  thread_todo = [&](Eventloop* eventloop){Default_thread(eventloop,before_loop_todo_);};
  eventloopthread_ = new Eventloopthread(thread_todo);
  eventloop_ = eventloopthread_->Get_eventloop_();
  net::Socket::Stringtonet(ipaddr.c_str(),&sockaddr_.sin_addr.s_addr);
  sockaddr_.sin_family = AF_INET;
  sockaddr_.sin_port = htons(port);
  while(loop){
    if(connect(socket_->Get_socket(),reinterpret_cast<sockaddr*>(&sockaddr_),sizeof(sockaddr_in)) != -1){
      break;
    }
  }
  eventloop_->Run_in_thread([this]{
    base::Channel* channel = eventloop_->Get_free_channel(socket_->Get_socket());
    net::Connect* connect = eventloop_->connectpool_->Get_Connect(channel);
    connect->Set_address(sockaddr_);

    connect->buffer_.Set_able_read_callback(message_callback_);
    connect->buffer_.Set_able_close_callback(close_callback_);
    connect->buffer_.Set_able_user_close_callback(Default_user_close);
    connect->Add_timejob_after_sec("heart beat",[connect]{connect->Send_heartbeat();},1,_C::CLIENT_HEART_BEAT_EVERY_SEC,_C::TIMEJOB_FOREVER);
    connect_over_callback_(connect);
    channel->Enableread(); //Enable recv data
    channel->Add_to_epoll();
  });
  return true;
};
bool Tcpclient::Startclient(std::string& ipaddr,int port,Eventloop* eventloop_){
  net::Socket::Stringtonet(ipaddr.c_str(),&sockaddr_.sin_addr.s_addr);
  sockaddr_.sin_family = AF_INET;
  sockaddr_.sin_port = htons(port);
  if(connect(socket_->Get_socket(),reinterpret_cast<sockaddr*>(&sockaddr_),sizeof(sockaddr_in)) == -1){
    return false;
  }
  eventloop_->Run_in_thread([this,eventloop_]{
    base::Channel* channel = eventloop_->Get_free_channel(socket_->Get_socket());
    net::Connect* connect = eventloop_->connectpool_->Get_Connect(channel);
    connect->Set_address(sockaddr_);

    connect->buffer_.Set_able_read_callback(message_callback_);
    connect->buffer_.Set_able_close_callback(close_callback_);
    connect->buffer_.Set_able_user_close_callback(Default_user_close);
    connect->Add_timejob_after_sec("heart beat",[connect]{connect->Send_heartbeat();},0,_C::CLIENT_HEART_BEAT_EVERY_SEC,_C::TIMEJOB_FOREVER);
    connect_over_callback_(connect);
    channel->Enableread(); //Enable recv data
    channel->Add_to_epoll();
  });
  return true;
};
void Tcpclient::Default_thread(Eventloop* eventloop,eventloop_func before_loop_todo){
  net::Connectpool* connectpool = new net::Connectpool(eventloop);
  eventloop->connectpool_ = connectpool;
  before_loop_todo(eventloop);
  eventloop->Loop();
};
void Tcpclient::Default_message(net::Connect* connect){
  connect->Read_callback();
};
void Tcpclient::Default_close(net::Connect* connect){
  connect->Close_callback();
};
void Tcpclient::Default_user_close(net::Connect* connect){
  connect->User_want_close_callback();
};

} // namespace net_tools